// 《围棋》作者版权所有。版权所有。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

// go:build goexperiment.staticlockranking 
// +build goexperiment.staticlockranking 

package runtime

import (
	"runtime/internal/atomic"
	"unsafe"
)

// /worldIsStopped以原子方式访问以跟踪世界站。1==世界
// 已停止。
var worldIsStopped uint32

// lockRankStruct嵌入互斥锁
type lockRankStruct struct {
	// 锁的静态锁排序
	rank lockRank
	// 填充字段以确保lockRankStruct是8字节的倍数，即使在
	// 32位系统上也是如此。
	pad int
}

func lockInit(l *mutex, rank lockRank) {
	l.rank = rank
}

func getLockRank(l *mutex) lockRank {
	return l.rank
}

// lockWithRank类似于lock（l），但允许调用方在获取非静态锁时指定锁级别
// 。
// 
// 请注意，我们需要注意堆栈拆分：
// 
// 此函数不是nosplit，因此它可能在函数入口拆分。这可能会在锁顺序中引入一个新的边缘，但与此调用之前的任何其他（nosplit）调用（包括对lock（）本身的调用）没有区别。
// 
// 但是，我们切换到systemstack来记录持有的锁，以确保
// 我们记录了准确的锁顺序。e、 例如，如果没有systemstack，堆栈
// lock2（）项上的拆分将记录在l之后的堆栈拆分锁，
// ，即使l实际上尚未锁定。
func lockWithRank(l *mutex, rank lockRank) {
	if l == &debuglock || l == &paniclk {
		// 调试锁仅用于println/printlock（）。不要为它做锁
		// 排名记录，因为当
		// 打印出下面的锁排序问题时会使用print/println。
		// 
		// paniclk仅用于致命投掷/恐慌。不要为它做锁
		// 排名记录，因为我们在报告
		// 锁排序问题后抛出。此外，在任何锁（我们可能会惊慌的任何地方）有效锁定后，可能会使用paniclk 
		// 这部分订单不包括在内。
		lock2(l)
		return
	}
	if rank == 0 {
		rank = lockRankLeafRank
	}
	gp := getg()
	// 记录新类。
	systemstack(func() {
		i := gp.m.locksHeldLen
		if i >= len(gp.m.locksHeld) {
			throw("too many locks held concurrently for rank checking")
		}
		gp.m.locksHeld[i].rank = rank
		gp.m.locksHeld[i].lockAddr = uintptr(unsafe.Pointer(l))
		gp.m.locksHeldLen++

		// i是正在获取的锁的索引
		if i > 0 {
			checkRanks(gp, gp.m.locksHeld[i-1].rank, rank)
		}
		lock2(l)
	})
}

// nosplit，以确保可以在尽可能多的上下文中调用它。
// go:nosplit 
func printHeldLocks(gp *g) {
	if gp.m.locksHeldLen == 0 {
		println("<none>")
		return
	}

	for j, held := range gp.m.locksHeld[:gp.m.locksHeldLen] {
		println(j, ":", held.rank.String(), held.rank, unsafe.Pointer(gp.m.locksHeld[j].lockAddr))
	}
}

// acquireLockRank获取与互斥锁无关的列组
// 
// 此函数可以在nosplit上下文中调用，因此必须为nosplit。
// go:nosplit 
func acquireLockRank(rank lockRank) {
	gp := getg()
	// 记录新类。请参阅对lockWithRank的评论。
	systemstack(func() {
		i := gp.m.locksHeldLen
		if i >= len(gp.m.locksHeld) {
			throw("too many locks held concurrently for rank checking")
		}
		gp.m.locksHeld[i].rank = rank
		gp.m.locksHeld[i].lockAddr = 0
		gp.m.locksHeldLen++

		// i是正在获取的锁的索引
		if i > 0 {
			checkRanks(gp, gp.m.locksHeld[i-1].rank, rank)
		}
	})
}

// checkRanks检查goroutine最近是否获得了一个等级为“prevRank”的锁
// 现在可以获取等级为“rank”的锁。
// 
// go:systemstack 
func checkRanks(gp *g, prevRank, rank lockRank) {
	rankOK := false
	if rank < prevRank {
		// 如果秩<prevRank，那么我们肯定有秩错误
		rankOK = false
	} else if rank == lockRankLeafRank {
		// 如果新锁是叶锁，那么前面的锁可以是除另一个叶锁以外的任何锁。
		rankOK = prevRank < lockRankLeafRank
	} else {
		// 我们现在已经验证了锁的总排名，但是我们
		// 还强制执行
		// lockPartialOrder指定的偏序。只有在lockPartialOrder表中明确列出
		// 的锁。
		// 时，才能同时获取两个具有相同等级
		list := lockPartialOrder[rank]
		for _, entry := range list {
			if entry == prevRank {
				rankOK = true
				break
			}
		}
	}
	if !rankOK {
		printlock()
		println(gp.m.procid, " ======")
		printHeldLocks(gp)
		throw("lock ordering problem")
	}
}

// 请参阅关于堆栈拆分的lockWithRank评论。
func unlockWithRank(l *mutex) {
	if l == &debuglock || l == &paniclk {
		// 请参见lockWithRank开头的注释。
		unlock2(l)
		return
	}
	gp := getg()
	systemstack(func() {
		found := false
		for i := gp.m.locksHeldLen - 1; i >= 0; i-- {
			if gp.m.locksHeld[i].lockAddr == uintptr(unsafe.Pointer(l)) {
				found = true
				copy(gp.m.locksHeld[i:gp.m.locksHeldLen-1], gp.m.locksHeld[i+1:gp.m.locksHeldLen])
				gp.m.locksHeldLen--
				break
			}
		}
		if !found {
			println(gp.m.procid, ":", l.rank.String(), l.rank, l)
			throw("unlock without matching lock acquire")
		}
		unlock2(l)
	})
}

// releaseLockRank释放与互斥锁无关的列组
// 
// 此函数可以在nosplit上下文中调用，因此必须是nosplit。
// go:nosplit 
func releaseLockRank(rank lockRank) {
	gp := getg()
	systemstack(func() {
		found := false
		for i := gp.m.locksHeldLen - 1; i >= 0; i-- {
			if gp.m.locksHeld[i].rank == rank && gp.m.locksHeld[i].lockAddr == 0 {
				found = true
				copy(gp.m.locksHeld[i:gp.m.locksHeldLen-1], gp.m.locksHeld[i+1:gp.m.locksHeldLen])
				gp.m.locksHeldLen--
				break
			}
		}
		if !found {
			println(gp.m.procid, ":", rank.String(), rank)
			throw("lockRank release without matching lockRank acquire")
		}
	})
}

// 请参阅关于堆栈拆分的lockWithRank评论。
func lockWithRankMayAcquire(l *mutex, rank lockRank) {
	gp := getg()
	if gp.m.locksHeldLen == 0 {
		// 如果没有其他锁持有，则不可能出现锁排序问题
		return
	}

	systemstack(func() {
		i := gp.m.locksHeldLen
		if i >= len(gp.m.locksHeld) {
			throw("too many locks held concurrently for rank checking")
		}
		// 临时将此锁添加到锁列表中，因此如果存在锁排序问题，
		// checkRanks（）将打印列表，包括此锁。
		gp.m.locksHeld[i].rank = rank
		gp.m.locksHeld[i].lockAddr = uintptr(unsafe.Pointer(l))
		gp.m.locksHeldLen++
		checkRanks(gp, gp.m.locksHeld[i-1].rank, rank)
		gp.m.locksHeldLen--
	})
}

// nosplit以确保可以在尽可能多的上下文中调用它。
// go:nosplit 
func checkLockHeld(gp *g, l *mutex) bool {
	for i := gp.m.locksHeldLen - 1; i >= 0; i-- {
		if gp.m.locksHeld[i].lockAddr == uintptr(unsafe.Pointer(l)) {
			return true
		}
	}
	return false
}

// /assertlockhold在调用方未持有l时抛出。
// 
// nosplit以确保可以在尽可能多的上下文中调用它。
// go:nosplit 
func assertLockHeld(l *mutex) {
	gp := getg()

	held := checkLockHeld(gp, l)
	if held {
		return
	}

	// 从系统堆栈崩溃，以避免可能导致
	// 其他问题的拆分。
	systemstack(func() {
		printlock()
		print("caller requires lock ", l, " (rank ", l.rank.String(), "), holding:\n")
		printHeldLocks(gp)
		throw("not holding required lock!")
	})
}

// assertRankHeld在调用者未持有秩为r的互斥时抛出。
// 
// 这比AssertLockHold精度低，但可用于无法使用精确互斥体的
// 指针的位置。
// 
// nosplit以确保可以在尽可能多的上下文中调用它。
// go:nosplit 
func assertRankHeld(r lockRank) {
	gp := getg()

	for i := gp.m.locksHeldLen - 1; i >= 0; i-- {
		if gp.m.locksHeld[i].rank == r {
			return
		}
	}

	// 从系统堆栈崩溃，以避免可能导致
	// 其他问题的拆分。
	systemstack(func() {
		printlock()
		print("caller requires lock with rank ", r.String(), "), holding:\n")
		printHeldLocks(gp)
		throw("not holding required lock!")
	})
}

// worldStopped注意到世界已经停止了。
// 
// 调用方必须持有worldsema。
// 
// nosplit以确保可以在尽可能多的上下文中调用它。
// go:nosplit 
func worldStopped() {
	if stopped := atomic.Xadd(&worldIsStopped, 1); stopped != 1 {
		systemstack(func() {
			print("world stop count=", stopped, "\n")
			throw("recursive world stop")
		})
	}
}

// /世界开始了，世界正在开始。
// 
// 调用方必须持有worldsema。
// 
// nosplit以确保可以在尽可能多的上下文中调用它。
// go:nosplit 
func worldStarted() {
	if stopped := atomic.Xadd(&worldIsStopped, -1); stopped != 0 {
		systemstack(func() {
			print("world stop count=", stopped, "\n")
			throw("released non-stopped world stop")
		})
	}
}

// nosplit确保可以在尽可能多的上下文中调用它。
// go:nosplit 
func checkWorldStopped() bool {
	stopped := atomic.Load(&worldIsStopped)
	if stopped > 1 {
		systemstack(func() {
			print("inconsistent world stop count=", stopped, "\n")
			throw("inconsistent world stop count")
		})
	}

	return stopped == 1
}

// /assertWorldStopped在世界未停止时抛出。它不检查
// 我阻止了世界。
// 
// nosplit以确保可以在尽可能多的上下文中调用它。
// go:nosplit 
func assertWorldStopped() {
	if checkWorldStopped() {
		return
	}

	throw("world not stopped")
}

// AssertWorldStoppedOrlockHold在世界未停止且未持有传递的锁时抛出。
// 
// nosplit以确保可以在尽可能多的上下文中调用它。
// go:nosplit 
func assertWorldStoppedOrLockHeld(l *mutex) {
	if checkWorldStopped() {
		return
	}

	gp := getg()
	held := checkLockHeld(gp, l)
	if held {
		return
	}

	// 从系统堆栈崩溃，以避免可能导致
	// 其他问题的拆分。
	systemstack(func() {
		printlock()
		print("caller requires world stop or lock ", l, " (rank ", l.rank.String(), "), holding:\n")
		println("<no world stop>")
		printHeldLocks(gp)
		throw("no world stop or required lock!")
	})
}
